
#include <stdio.h>
#include <stdlib.h>
#include "express.h"
#include "resolve.h"
#include "classes.h"

#define SCHEMA_FILE_PREFIX	"Sdai"

int multiple_inheritance = 0;

/***********************************************************************
 I changed this function from FILEcreate() in class_misc.c in this way. 
 The message that gets printed to the file says fedex_os instead 
 of fedex_plus - DAS
***********************************************************************/
FILE*
myFILEcreate (const char * filename)
{
    FILE* file;
    const char * fn;
    
    if ((file = fopen (filename, "w")) == NULL) {
	printf ("**Error in myFILEcreate:  unable to create file %s ** \n", filename);
	return (NULL);
    }

    fprintf (file, "#ifndef  %s\n", fn = StrToConstant (filename));
    fprintf (file, "#define  %s\n", fn );

	fprintf(file,"// This file was generated by fedex_os.  You probably don't want to edit\n");
	fprintf(file,"// it since your modifications will be lost if fedex_os is used to\n");
	fprintf(file,"// regenerate it.\n");
    return (file);
    
}

void
SCOPEPrintHooks(Scope scope, FILE *os_hooks_file,Schema schema,Express model)
{
    const char * entnm;
    Linked_List list;
    char nm[BUFSIZ];
    char classNm [BUFSIZ];

    DictionaryEntry de;
    int index = 0;

    /* do \'new\'s for types descriptors  */
/*
    SCOPEdo_types(scope,t,de)
      TYPEprint_new (t, files,schema);
    SCOPEod;
*/
    /* do \'new\'s for entity descriptors  */
    list = SCOPEget_entities_superclass_order (scope);
    fprintf (os_hooks_file, "\n#if 0\n"); 
    fprintf (os_hooks_file, "// comment all of these out since they don't work with ObjectStore (an ObjectStore bug).\n\n"); 

    fprintf (os_hooks_file, "// ***********  Make the access hook call for each entity ********** \n"); 
    LISTdo (list, e, Entity);
	entnm = ENTITYget_classname (e);

	fprintf (os_hooks_file, "    db->set_access_hooks(\"%s\", %s_access_hook_in, 0,0,0,0);\n", entnm, entnm); 
    LISTod;

    fprintf (os_hooks_file, "// ***********  Make the access hook call for each type as needed ********** \n"); 
    SCOPEdo_types(scope,t,de)
      if( TYPEis_select(t) )
      {
	  strncpy (classNm, SelectName (TYPEget_name (t)), BUFSIZ);
	  fprintf (os_hooks_file, "    db->set_access_hooks(\"%s\", %s_access_hook_in, 0,0,0,0);\n", classNm, classNm); 
      }
      else if ( TYPEis_enumeration(t) ) {
	  strncpy (classNm, TYPEget_ctype (t), BUFSIZ);
	  fprintf (os_hooks_file, "    db->set_access_hooks(\"%s\", %s_access_hook_in, 0,0,0,0);\n", classNm, classNm); 
	  fprintf (os_hooks_file, "    db->set_access_hooks(\"%ss\", %ss_access_hook_in, 0,0,0,0);\n", classNm, classNm); 
      }
      else if ( TYPEis_aggregate(t) ) {
	  strncpy (classNm, SelectName (TYPEget_name (t)), BUFSIZ);
	  fprintf (os_hooks_file, "    aggr db->set_access_hooks(\"%s\", %s_access_hook_in, 0,0,0,0);\n", classNm, classNm); 
      }
    SCOPEod;
    fprintf (os_hooks_file, "\n#endif\n"); 

    LISTfree(list);
}

void
SCOPEPrint(Scope scope, FILE *osschema_file,Schema schema,Express model)
{
    const char * entnm;
    Linked_List list;
    char nm[BUFSIZ];
    const char * enum_nm;  /*  pointer to class name  */

    DictionaryEntry de;
    int index = 0;

    /* do \'new\'s for types descriptors  */
/*
    SCOPEdo_types(scope,t,de)
      TYPEprint_new (t, files,schema);
    SCOPEod;
*/

    fprintf (osschema_file, "// ***********  Specify the SdaiModel_contents_%s class to be persistent ********** \n", SCHEMAget_name(schema)); 
    fprintf (osschema_file, "\nOS_MARK_SCHEMA_TYPE(SdaiModel_contents_%s)\n", 
	   SCHEMAget_name(schema)); 

    list = SCOPEget_entities_superclass_order (scope);

    fprintf (osschema_file, "\n// ***********  Specify the entities to be persistent ********** \n"); 
    LISTdo (list, e, Entity);
	entnm = ENTITYget_classname (e);
	fprintf (osschema_file, "OS_MARK_SCHEMA_TYPE(%s)\n", entnm); 
    LISTod;

    /*  fill in the values for the type descriptors */
    /*  and print the enumerations  */
    fprintf (osschema_file, "\n// ***********  Specify the types to be persistent ********** \n"); 
    SCOPEdo_types(scope,t,de)
      switch(TYPEget_body(t)->type)
      {
	case enumeration_:
	{
	    enum_nm = TYPEget_ctype (t);
	    fprintf(osschema_file, "OS_MARK_SCHEMA_TYPE(%s)\n", enum_nm);
	    fprintf(osschema_file, "OS_MARK_SCHEMA_TYPE(%ss)\n",enum_nm);
	    break;
	}
	case select_:
	{
	    /*   do the select aggregates here  */
	    strncpy (nm, SelectName (TYPEget_name (t)), BUFSIZ);
	    fprintf(osschema_file, "OS_MARK_SCHEMA_TYPE(%s)\n", nm);
	    fprintf(osschema_file, "OS_MARK_SCHEMA_TYPE(%ss)\n",nm);
	    break;
	}
	case aggregate_: /* aggregate_ should not happen? DAS */
	case array_:
	case bag_:
	case set_:
	case list_:
	default:
	{
	    break;
	}
      }
/*      TYPEprint_descriptions (t, files, schema);*/

    SCOPEod;

    /*  build the typedefs  */
/*
    SCOPEdo_types(scope,t,de)
      if( ! (TYPEis_select(t) ))
	TYPEprint_typedefs (t, files ->inc, schema);
    SCOPEod;
*/
    /*  do the select definitions next, since they depend on the others  */
/*
    fprintf (files->inc, "\n//\t***** Build the SELECT Types  \t\n");
    fprintf (files->init, "\n//\t***** Add the TypeDescriptor's to the SELECT Types  \t\n");
    SCOPEdo_types(scope,t,de)
      if( TYPEis_select(t) )
	TYPEselect_print (t, files, schema);
    SCOPEod;
*/
    LISTfree(list);
}

/* This corresponds to fedex_plus's SCHEMAprint() function.
   It creates and closes the files that will be generated. */

void
osSCHEMAprint (Schema schema, FILES* files, Express model)
{
    char fnm [BUFSIZ], *np;
    char schnm[BUFSIZ];

    FILE *osschema_file;
    FILE *os_hooks_file_h;
    FILE *os_hooks_file_cc;
    FILE* os_makefile = files -> make;
/*
    FILE* osschema_file;

    FILE* incfile;
    FILE* schemafile = files -> incall;
    FILE* schemainit = files -> initall;
    FILE *initfile;    
*/    

    /**********  create files based on name of schema	***********/
    /*  return if failure			*/
    /*  1.  header file				*/
    sprintf(schnm,"%s%s", SCHEMA_FILE_PREFIX, 
	    StrToUpper (SCHEMAget_name(schema)));
    sprintf(fnm,"osschema_%s.cc",schnm);

/* print a new make_schema called make_schema_os that includes the additional
   ObjectStore files generated */
    fprintf (os_makefile, "\\\n\t%s.o ",schnm);
    fprintf (os_makefile, "\\\n\t%s.init.o ",schnm);
    fprintf (os_makefile, "\\\n\tosdb_%s.o ",schnm);

    if (! (osschema_file = myFILEcreate (fnm)))  return;
    fprintf (osschema_file, "/* %cId$  */ \n",'\044');

    fprintf (osschema_file,"\n");
    fprintf (osschema_file,"#include <ostore/ostore.hh>    // Required to access ObjectStore Class Library\n");
    fprintf (osschema_file,
	     "//#include <ostore/coll.hh> // if you use ostore collections\n");
    fprintf (osschema_file,
	     "    // manschem.hh - required at least for ossg to \n");
    fprintf (osschema_file,
	     "    // know what the OS_MARK_SCHEMA_TYPE() macros are\n");
    fprintf (osschema_file,
	     "#include <ostore/manschem.hh>\n");


    fprintf (osschema_file, "\n// This file specifies which classes from the schema-independent SCL \n// libs should persist\n");
    fprintf (osschema_file, "#include <scl_osschema.h> \n");

    fprintf (osschema_file, "\n#include <%s.h> \n", schnm);

    fprintf (osschema_file, "\n// Specify the types in this schema to be persistent in ObjectStore \n// (you don't actually call this function though)\n");
    fprintf (osschema_file, "void \ndummy_%s()\n{\n\n", schnm);

	/* really, create calls for entity constructors */
    SCOPEPrint(schema, osschema_file,schema,model);

    fprintf (osschema_file, "\n} // end dummy_%s()\n\n",schnm);

    /**********  close the files	***********/
    FILEclose (osschema_file);

/****************
Generate access hooks for reinitializing EntityDescriptor* in each SCLP23(Application_instance)
*****************/
    sprintf(fnm,"osdb_%s.cc",schnm);
    if (! (os_hooks_file_cc = myFILEcreate (fnm)))  return;

    sprintf(fnm,"osdb_%s.h",schnm);
    if (! (os_hooks_file_h = myFILEcreate (fnm)))  return;

    fprintf (os_hooks_file_cc, "/* %cId$  */ \n",'\044');
    fprintf (os_hooks_file_cc,"\n");
    fprintf (os_hooks_file_cc,"#include <%s>\n", fnm);
    fprintf (os_hooks_file_cc, "\n#include <%s.h> \n", schnm);

    fprintf (os_hooks_file_h, "/* %cId$  */ \n",'\044');
    fprintf (os_hooks_file_h,"\n");
    fprintf (os_hooks_file_h,"#include <ostore/ostore.hh>    // Required to access ObjectStore Class Library\n");
    fprintf (os_hooks_file_h,
	     "//#include <ostore/coll.hh> // if you use ostore collections\n");
    fprintf (os_hooks_file_h,
	     "    // manschem.hh - required at least for ossg to \n");
    fprintf (os_hooks_file_h,
	     "    // know what the OS_MARK_SCHEMA_TYPE() macros are\n");
    fprintf (os_hooks_file_h,
	     "#include <ostore/manschem.hh>\n");

    fprintf (os_hooks_file_h, "\nvoid \nset_hooks_%s(os_database *db);\n\n", schnm);
    fprintf (os_hooks_file_h,"#endif");

    fprintf (os_hooks_file_cc, "\n// This initializes an ObjectStore database with the access hook functions for this schema \n");
    fprintf (os_hooks_file_cc, "void \nset_hooks_%s(os_database *db)\n{\n\n", schnm);

    fprintf (os_hooks_file_cc, 
	     "    db->set_default_null_illegal_pointers(1);\n\n");

	/* really, create calls for entity constructors */
    SCOPEPrintHooks(schema, os_hooks_file_cc,schema,model);

    fprintf (os_hooks_file_cc, "\n} // end set_hooks_%s()\n\n",schnm);

    /**********  close the files	***********/
    FILEclose (os_hooks_file_h);
    FILEclose (os_hooks_file_cc);
}


void
os_print_schemas_separate (Express express, FILES* files)
{
    DictionaryEntry de;
    Schema schema;
    
    /**********  do all schemas	***********/
    DICTdo_init(express->symbol_table,&de);
    while (0 != (schema = (Scope)DICTdo(&de))) {
	    osSCHEMAprint(schema, files, express);	
    }
    fprintf (files->make, "\n");
    fclose(files->make);
}

static void
fedex_os_usage()
{
        fprintf(stderr,"usage: %s [-v] [-d #] [-p <object_type>] {-w|-i <warning>} express_file\n",EXPRESSprogram_name);
	exit(2);
}

int Handle_FedPlus_Args(int i, char *arg)
{
    if( ((char)i == 's') || ((char)i == 'S'))
      printf("used -%c option\n", (char)i);
/*
	multiple_inheritance = 0;
*/
    return 0;
}

void 
print_file(Express express)
{
	extern void RESOLUTIONsucceed(void);
	File_holder  files;

	/* print a new make_schema called make_schema_os that includes the 
	   additional ObjectStore files generated */
	if (((files.make) = fopen ("make_schema_os", "w")) == NULL) {
	    printf ("**Error in print_file:  unable to open file make_schema_os ** \n");
	    return;
	}
/* 
May want to change the generator to generate a new file that defines some 
of these:
OS_SCL_SCHEMA_OBJ= osdb_SdaiEB203_PRODUCT_IDENTIFICATION.o

SCHEMA_SRC= osschema_SdaiEB203_PRODUCT_IDENTIFICATION.cc
SCL_OS_OBJ= 
APP_SCHEMA_SRC= osschema.cc
APP_SCHEMA_OBJ= osschema.o
SCHEMA_SRC2= 
APP_SCHEMA_HDRS=
 #APP_SCHEMA_DB= $(OS_SCHEMA_DB_DIR)scl.adb
 #APP_SCHEMA_DB= /proj/niiip/src/ds/proto/ostr2/c3appldb.adb
APP_SCHEMA_DB= /proj/framedb/niiipdemo97/c3appl_db_niiip.adb
LIB_SCHEMA_DBS= $(OS_ROOTDIR)/lib/liboscol.ldb
#LIB_SCHEMA_DBS=
 #PIB_DB= /proj/framewrk/src/objectstore_persist_stuff/database_pib.db
PIB_DB= /proj/framedb/niiipdemo97/c3database_niiip.db
*/
	fprintf (files.make, "OFILES =  schema.o SdaiAll.o compstructs.o ");

	resolution_success();
	os_print_schemas_separate (express, &files);
}    

void resolution_success(void)
{
	printf("Resolution successful.  Writing ObjectStore-related C++ output...\n");
}

int success(Express model)
{
	printf("Finished writing files.\n");
	return(0);
}

/* This function is called from main() which is part of the NIST Express 
   Toolkit.  It assigns 2 pointers to functions which are called in main() */
void
EXPRESSinit_init() 
{
	EXPRESSbackend = print_file;
	EXPRESSsucceed = success;
	EXPRESSgetopt = Handle_FedPlus_Args;
  /* so the function getopt (see man 3 getopt) will not report an error */
/*	strcat(EXPRESSgetopt_options, "");*/
	ERRORusage_function = fedex_os_usage;
}
